//
// Created by Administrator on 2020/7/2.
//
#include "NEFFmpeg.h"

NEFFmpeg::NEFFmpeg(JavaCallHelper *javaCallHelper, char *dataSource) {
    this->javaCallHelper = javaCallHelper;

    //java："hello"
    //c 字符串已\0结尾 ： "hello\0"
    this->dataSource = new char[strlen(dataSource) + 1];

    //拷贝字符串是因为jni中会调用env->Release****()方法释放内存，导致dataSource变成指向一块空内存的悬空指针
    strcpy(this->dataSource, dataSource);
}

NEFFmpeg::~NEFFmpeg() {
    DELETE(dataSource);
    DELETE(javaCallHelper);
}

/**
 * 准备任务
 * @param args
 * @return
 */
void *task_prepare(void *args) {
    NEFFmpeg *ffmpeg = static_cast<NEFFmpeg *>(args);
    ffmpeg->_prepare();
    //必须返回0
    return 0;
}

/**
 * 播放准备
 * 子线程任务
 */
void NEFFmpeg::_prepare() {
    avFormatContext = avformat_alloc_context();
    AVDictionary *dictionary = 0;
    av_dict_set(&dictionary, "timeout", "10000000", 0);
    int ret = avformat_open_input(&avFormatContext, dataSource, 0, &dictionary);
    av_dict_free(&dictionary);

    if (ret) {
        //为0则代表失败，回调给java
        LOGE("打开媒体失败：%s", av_err2str(ret));
        javaCallHelper->onError(THREAD_CHILD, ret);
        return;
    }
    ret = avformat_find_stream_info(avFormatContext, 0);
    if (ret < 0) {
        LOGE("查找数据流信息失败：%s", av_err2str(ret));
        return;
    }
    for (int i = 0; i < avFormatContext->nb_streams; ++i) {
        AVStream *stream = avFormatContext->streams[i];
        AVCodecParameters *codecParameters = stream->codecpar;
        AVCodec *avCodec = avcodec_find_decoder(codecParameters->codec_id);
        if (!avCodec) {
            LOGE("不支持的解码格式！");
            return;
        }

        AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
        if (!avCodecContext) {
            LOGE("创建解码器上下文失败！");
            return;
        }
        ret = avcodec_parameters_to_context(avCodecContext, codecParameters);
        if (ret < 0) {
            LOGE("设置解码上下文失败！");
            return;
        }
        ret = avcodec_open2(avCodecContext, avCodec, 0);
        if (ret) {
            LOGE("解码失败！");
            return;
        }
        if (codecParameters->codec_type == AVMEDIA_TYPE_AUDIO) {
//            audioChannel = new AudioChannel(i,avCodecContext);
        } else if (codecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
            int fps = static_cast<int>(av_q2d(stream->avg_frame_rate));
            videoChannel = new VideoChannel(i, avCodecContext, fps);
            videoChannel->setRenderCallback(renderCallback);
        }
    }//end for

    if (!audioChannel && !videoChannel) {
        LOGE("没有音视频数据！");
    }
    javaCallHelper->onPrepared(THREAD_CHILD);
}

/**
 * 播放准备
 */
void NEFFmpeg::prepare() {
    pthread_create(&pid_prepare, 0, task_prepare, this);
}


void *task_start(void *args) {
    NEFFmpeg *ffmpeg = static_cast<NEFFmpeg *>(args);
    ffmpeg->_start();
    return 0;
}

/**
 * 开始播放
 * 子线程任务
 */
void NEFFmpeg::_start() {
    while (isPlaying) {
        if (videoChannel && videoChannel->packets.size() > 50) {
            av_usleep(10 * 1000);
            continue;
        }

        AVPacket *packet = av_packet_alloc();

        int ret = av_read_frame(avFormatContext, packet);
        if (!ret) {
            //ret 为 0 表示成功
            //要判断流类型，是视频还是音频
            if (videoChannel && packet->stream_index == videoChannel->streamId) {
                //往视频编码数据包队列中添加数据
                videoChannel->packets.push(packet);
            } else if (audioChannel && packet->stream_index == audioChannel->streamId) {
                //往音频编码数据包队列中添加数据
//                audioChannel->packets.push(packet);
            }
        } else if (ret == AVERROR_EOF) {
            //表示读完了
            //要考虑读完了，是否播完了的情况
        } else {
            LOGE("读取音视频数据包失败");
            if (javaCallHelper) {
                javaCallHelper->onError(THREAD_CHILD, FFMPEG_READ_PACKETS_FAIL);
            }
            break;
        }
    }//end while

    isPlaying = 0;
    //停止解码播放（音频和视频）
    videoChannel->stop();
    audioChannel->stop();
}

/**
 * 开始播放
 */
void NEFFmpeg::start() {
    isPlaying = 1;
    if (videoChannel) {
        videoChannel->start();
    }
    pthread_create(&pid_start, 0, task_start, this);
}

void NEFFmpeg::setRenderCallback(RenderCallback renderCallback) {
    this->renderCallback = renderCallback;
}



